package com.base.util;

import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Environment;
import android.text.TextUtils;
import android.util.DisplayMetrics;

import androidx.annotation.Nullable;

import com.base.app.BaseApp;
import com.loyal.core.helper.FileHelper;
import com.loyal.core.helper.TimeHelper;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class MemoryUtil extends FileHelper {
    private static final String DIR_PACKAGE = initPackageDir() + File.separator;
    public static final String PATH_PRIVATE = DIR_PACKAGE;

    public static final String DIR_APK = PATH_PRIVATE + "apk" + File.separator;//更新apk目录
    public static final String DIR_AUDIO = PATH_PRIVATE + "audio" + File.separator;//音频目录
    public static final String DIR_CONFIG = PATH_PRIVATE + "config" + File.separator;//配置
    public static final String DIR_CACHE = PATH_PRIVATE + "cache" + File.separator;//缓存
    public static final String DIR_CRASH = PATH_PRIVATE + "crash" + File.separator;//闪退
    public static final String DIR_IMAGE = PATH_PRIVATE + "image" + File.separator;//图片目录
    public static final String DIR_LIB = PATH_PRIVATE + "lib" + File.separator;//身份证读卡器授权目录;
    public static final String DIR_LOG = PATH_PRIVATE + "log" + File.separator;//日志
    public static final String DIR_VIDEO = PATH_PRIVATE + "video" + File.separator;//视频目录
    public static final String DIR_SLAM = PATH_PRIVATE + "slam" + File.separator;//底盘目录
    public static final String DIR_SLAM_MAP = DIR_SLAM + "map" + File.separator;//底盘地图目录

    public static final String FILE_VIDEO_DEBUG = "video.mp4";//视频文件名
    public static final String FILE_VIDEO_ADVERT = "子曰宣传片-大宽.mp4";//视频文件名
    public static final String FILE_AUDIO_DEBUG = "audio.amr";//音频文件名
    //不要更改此文件名，否则安装时会找不到文件
    public static final String APK_NAME = "rbt-test.apk";
    public static final String NAME_CONFIG = "config.db";
    private static final String NAME_DEV = "dev.txt";
    public static final String TYPE_MAP = ".stcm";//地图文件名后缀
    private static final String[] DIR_PATHS = new String[]{
            DIR_APK, DIR_AUDIO, DIR_CACHE, DIR_CONFIG, DIR_CRASH, DIR_LIB, DIR_IMAGE,
            DIR_LOG, DIR_VIDEO, DIR_SLAM_MAP};

    private static boolean checkExternalValidate() {
        return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
    }

    private static String initPackageDir() {
        String dirPath;
        if (checkExternalValidate()) {
            File file = BaseApp.getInstance().getExternalFilesDir("");
            dirPath = null == file ? "" : file.getAbsolutePath();
        } else {
            dirPath = BaseApp.getInstance().getFilesDir().getAbsolutePath();
        }
        return dirPath;
    }

    public static String mapName(String mapId) {
        return String.format("map_%s%s", mapId, TYPE_MAP);
    }

    public static boolean nearlyFile(File file) {
        try {
            if (null == file || !file.exists() || file.length() == 0)
                return false;
            long time = file.lastModified();
            long current = new Date().getTime();
            return current - time <= TimeHelper.Duration.DAY / 2;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public static void mkPkgDirs() {
        for (String dirPath : DIR_PATHS) {
            mkDirs(dirPath);
        }
    }

    public static void deleteOldCrash() {
        File crashDir = new File(DIR_CRASH);
        if (!crashDir.exists())
            return;
        File[] crashFiles = crashDir.listFiles();
        if (null == crashFiles) {
            return;
        }
        for (File file : crashFiles) {
            if (!nearlyFile(file)) {
                delete(file);
            }
        }
    }

    public static void deleteOldLog() {
        File logDir = new File(DIR_LOG);
        if (!logDir.exists())
            return;
        File[] logFiles = logDir.listFiles();
        if (null == logFiles) {
            return;
        }
        for (File file : logFiles) {
            if (!nearlyFile(file)) {
                delete(file);
            }
        }
    }

    public static boolean upZipFile(String zipFile, String folderPath) {
        try (ZipFile zfile = new ZipFile(zipFile)) {
            // 转码为GBK格式，支持中文
            Enumeration<? extends ZipEntry> zList = zfile.entries();
            ZipEntry ze;
            byte[] buf = new byte[1024];
            while (zList.hasMoreElements()) {
                ze = zList.nextElement();
                // 列举的压缩文件里面的各个文件，判断是否为目录
                if (ze.isDirectory()) {
                    String dirStr = (folderPath + ze.getName()).trim();
                    File f = new File(dirStr);
                    mkDirs(f);
                    continue;
                }
                // ze.getName()会返回 script/start.script这样的，是为了返回实体的File
                File realFile = getRealFileName(folderPath, ze.getName());

                OutputStream os = new BufferedOutputStream(new FileOutputStream(realFile));
                InputStream is = new BufferedInputStream(zfile.getInputStream(ze));
                int readLen;
                // 进行一些内容复制操作
                while ((readLen = is.read(buf, 0, 1024)) != -1) {
                    os.write(buf, 0, readLen);
                }
                is.close();
                os.flush();
                os.close();
            }
            zfile.close();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    private static File getRealFileName(String baseDir, String absFileName) {
        absFileName = absFileName.replace("\\", "/");
        String[] dirs = absFileName.split("/");
        File ret = new File(baseDir);
        String substr;
        if (dirs.length > 1) {
            for (int i = 0; i < dirs.length - 1; i++) {
                substr = dirs[i];
                ret = new File(ret, substr);
            }
            if (!ret.exists())
                mkDirs(ret);
            substr = dirs[dirs.length - 1];
            ret = new File(ret, substr);
            return ret;
        } else {
            ret = new File(ret, absFileName);
        }
        return ret;
    }

    /**
     * 3个小时内是否更新安装过
     *
     * @return true 最近安装；false 不是最近安装
     */
    public static boolean nearUpdate(Context context) {
        PackageManager pm = context.getPackageManager();
        try {
            ApplicationInfo appInfo = pm.getApplicationInfo(context.getPackageName(), 0);
            String appFile = appInfo.sourceDir;
            long updateTimer = new File(appFile).lastModified();
            long current = new Date().getTime();
            long bet = current - updateTimer;
            return bet <= 3 * 60 * 60 * 1000L;
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }
    }

    /**
     * 读取身份证头像照片
     */
    public static Bitmap getIdCardBmp() {
        File file = new File(DIR_LIB, "zp.bmp");
        //--/storage/emulated/0/Android/data/com.traffic.idcard/wltlib/zp.bmp
        //--/storage/self/primary/Android/data/com.traffic.idcard/wltlib/zp.bmp
        try (FileInputStream fis = new FileInputStream(file)) {
            Bitmap bmp = BitmapFactory.decodeStream(fis);
            fis.close();
            return bmp;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * @param originalPath 源地址
     * @param targetPath   目标地址
     */
    public static void copyFolder(String originalPath, String targetPath) {
        if (TextUtils.isEmpty(originalPath) || TextUtils.isEmpty(targetPath)) return;
        File originalFile = new File(originalPath);
        if (!originalFile.exists()) return;

        File[] originalFiles = originalFile.listFiles();
        if (null == originalFiles) return;

        File targetFile = new File(targetPath);
        if (!targetFile.exists()) {
            mkDirs(targetFile);
        }
        for (File childOriginalFile : originalFiles) {
            if (!childOriginalFile.canRead()) return;
            String name = childOriginalFile.getName();
            File childTargetFile = new File(targetFile, name);
            if (childOriginalFile.isDirectory()) {
                copyFolder(childOriginalFile.getPath(), childTargetFile.getPath());
            } else if (childTargetFile.isFile()) {
                copyFile(childOriginalFile, targetFile);
            }
        }
    }

    public static void copyFile(File oldFile, File newFile) {
        try (FileInputStream inputStream = new FileInputStream(oldFile);
             FileOutputStream outputStream = new FileOutputStream(newFile)) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
            }
            outputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设备的状态信息
     */
    public static void writeDevLog(Activity activity) {
        File devFile = new File(DIR_LOG, NAME_DEV);
        boolean isTable = DevUtil.isTablet();
        int smallDp = DevUtil.smallWidth();
        String version = DevUtil.apkVersion(activity);
        DisplayMetrics mDisplayMetrics = new DisplayMetrics();
        activity.getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);

        String content = "是否table[" + isTable + "],\n" +
                "系统版本:[" + Build.VERSION.SDK_INT + "(" + Build.VERSION.RELEASE + ")],\n" +
                "程序版本:[" + version + "],\n" +
                "最小宽度限制符:[" + smallDp + "],\n" +
                "屏幕密度:[" + mDisplayMetrics.density + "],\n" +
                "densityDpi:[" + mDisplayMetrics.densityDpi + "],\n" +
                "metrics:[" + mDisplayMetrics.widthPixels + "*" + mDisplayMetrics.heightPixels + "],\n" +
                "realMetrics:[" + DevUtil.getDisplay(activity) + "]";
        content += ",\nSUPPORTED_ABIS:[" + Arrays.toString(Build.SUPPORTED_ABIS) + "]";

        write(devFile, content);
    }

    public static void saveSlamMap() {

    }

    /**
     * 查找地图
     * 加载地图到底盘
     * CompositeMapHelper compositeMapHelper = new CompositeMapHelper();
     * CompositeMap compositeMap = compositeMapHelper.loadFile(MemoryUtil.getMapfileName(RobotInfoDao.getMapid()));
     * mAgent.getRobotPlatform().setCompositeMap(compositeMap, new Pose());
     */
    public static @Nullable File getSlamMap(String mapName) {
        File mapDir = new File(DIR_SLAM_MAP);
        mkDirs(mapDir);
        File[] mapFiles = mapDir.listFiles();
        if (null == mapFiles || 0 == mapFiles.length)
            return null;
        File selectedMap = null;
        for (File child : mapFiles) {
            String childName = child.getName();
            if (!childName.endsWith(".stcm"))
                continue;
            if (childName.startsWith(mapName)) {
                selectedMap = child;
                break;
            }
        }

        return selectedMap;
    }

    /**
     * 计算文件的MD5哈希值
     *
     * @param filePath 文件路径
     * @return 文件的MD5哈希值
     * @throws NoSuchAlgorithmException 如果找不到MD5算法
     * @throws IOException              如果读取文件时发生错误
     */
    public static @Nullable String getFileMd5(String filePath) {
        try (FileInputStream fis = new FileInputStream(filePath)) {
            // 获取MD5消息摘要对象
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 创建文件输入流
            byte[] buffer = new byte[1024];
            int length;

            // 分块读取文件内容并更新消息摘要
            while ((length = fis.read(buffer)) != -1) {
                md.update(buffer, 0, length);
            }
            // 获取最终的哈希值
            byte[] digest = md.digest();

            // 将字节数组转换为十六进制字符串
            StringBuilder hexString = new StringBuilder();
            for (byte b : digest) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }

            return hexString.toString();
        } catch (IOException | NoSuchAlgorithmException e) {
            return null;
        }
    }
}
